package com.opengroupe.service.pc.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.opengroupe.dao.CandidatDao;
import com.opengroupe.dao.CategorieDao;
import com.opengroupe.dao.QuestionDao;
import com.opengroupe.dao.ReponseDao;
import com.opengroupe.dto.CandidatDto;
import com.opengroupe.entities.Candidat;
import com.opengroupe.entities.Categorie;
import com.opengroupe.entities.Question;
import com.opengroupe.entities.Reponse;
import com.opengroupe.service.pc.PCService;
import com.opengroupe.util.QrhException;

public class PCServiceImpl implements PCService {
	
	@Autowired
	private QuestionDao questionDao;
	
	@Autowired
	private CandidatDao candidatDao;
	
	@Autowired
	private CategorieDao categorieDao;
	
	@Autowired
	private ReponseDao reponseDao;

	public Question creerQuestion(Question question) throws Exception {
		if(question == null) {
			return null;
		}

		Question createdQuestion = questionDao.persist(question);
		return createdQuestion;
	}

	public Question modifierQuestion(Question question) throws QrhException {
		if(question == null) {
			return null;
		}

		if(question.getIdQuestion() == null) {
			String message = "L'identifiant de la question a modifie ne peut etre nul !";
			throw new QrhException(message);
		}

		try {
			return questionDao.merge(question);
		} catch (Exception e) {
			throw new QrhException();
		}
	}

	public void deleteCandidat(String emailCandidat) {
		candidatDao.deleteCascade(emailCandidat);
	}

	@Override
	@Transactional
	public void deleteQuestion(long idQuestion) {
		Question question = questionDao.findById((int) idQuestion);
		
		try {
			removeAllReponsesEventuellesFromQuestion(question);
			removeAllReponsesCorrectesFromQuestion(question);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		questionDao.deleteCascade(question);
	}
	
	@Override
	@Transactional
	public void deleteReponse(String idReponse) throws Exception {
		Reponse reponse = reponseDao.findById(Integer.parseInt(idReponse));
		
		List<Question> questionsDesReponsesEventuelles = reponse.getQuestions();
		for(Question question  : questionsDesReponsesEventuelles){
			removeReponseEventuelleFromQuestion(question, reponse);
		}
		
		List<Question> questionDesReponsesCorrectes = reponse.getQuestions_1();
		for(Question question  : questionDesReponsesCorrectes){
			removeReponseCorrecteFromQuestion(question, reponse);
		}
		
		reponseDao.remove(reponse);
	}
	
	private void removeReponseCorrecteFromQuestion(Question question, Reponse reponse) throws Exception{
		List<Reponse> reponsesCorrectes = question.getReponsesCorrectes();
		for (Iterator<Reponse> iterator = reponsesCorrectes.iterator(); iterator.hasNext();) {
			Reponse reponseCorrecte = (Reponse) iterator.next();
			if(reponseCorrecte.getIdReponse() == reponse.getIdReponse()){
				iterator.remove();
			}
		}
		questionDao.merge(question);
	}

	/**
	 * Enlève la réponse eventuelle de la question
	 * @param question
	 * @param reponse
	 * @throws Exception
	 */
	private void removeReponseEventuelleFromQuestion(Question question, Reponse reponse) throws Exception {
		List<Reponse> reponsesEventuelles = question.getReponsesEventuelles();
		for (Iterator<Reponse> iterator = reponsesEventuelles.iterator(); iterator.hasNext();) {
			Reponse reponseEventuelle = (Reponse) iterator.next();
			if(reponseEventuelle.getIdReponse() == reponse.getIdReponse()){
				iterator.remove();
			}
			
		}
		questionDao.merge(question);
	}

	/**
	 * Enlève toutes les réponses correctes de la question
	 * @param question
	 * @throws Exception
	 */
	@Transactional
	private void removeAllReponsesCorrectesFromQuestion(Question question) throws Exception {
		question.setReponsesCorrectes(new ArrayList<Reponse> ());
		questionDao.merge(question);
	}
	
	/**
	 * Enleve toutes les réponses éventuelles de la question
	 * @param question
	 * @throws Exception
	 */
	@Transactional
	private void removeAllReponsesEventuellesFromQuestion(Question question) throws Exception {
		question.setReponsesEventuelles(new ArrayList<Reponse> ());
		questionDao.merge(question);
	}

	@Override
	public Categorie modifierCategorie(Integer idCategorie, String libelleCategorie) throws Exception {
		Categorie categorie = null;
		try{
			categorie = categorieDao.findById(idCategorie);
			categorie.setLibelleCategorie(libelleCategorie);
			categorie = categorieDao.merge(categorie);
			return categorie;
		} catch (Exception e) {
			throw e;
		}
		
	}

	@Override
	public CandidatDto modifierCandidat(CandidatDto candidatDto) throws Exception{
		
		Candidat candidat = candidatDao.findById(candidatDto.getIdCandidat());
		
		candidat.setPrenomCandidat(candidatDto.getPrenomCandidat());
		candidat.setNomCandidat(candidatDto.getNomCandidat());
		candidat.setEmailCandidat(candidatDto.getEmailCandidat());
		candidat.setTelephoneCandidat(candidatDto.getTelephoneCandidat());
		try{
			candidatDao.merge(candidat);
		} catch (Exception e) {
			
		}
		
		return null;
	}

	@Override
	@Transactional
	public Question addReponsesEventuellesToQuestion(String idQuestion,List<String> idReponses) throws Exception {
		
		Question question = questionDao.findById(Integer.parseInt(idQuestion));
		List<Reponse> reponsesEventuelles = new ArrayList<Reponse>();
		
		for(String idReponse : idReponses){
			Reponse reponse = reponseDao.findById(Integer.parseInt(idReponse));
			reponsesEventuelles.add(reponse);
		}
		
		question.setReponsesEventuelles(reponsesEventuelles);
		
		try{
			question = questionDao.merge(question);
			return question;
		} catch (Exception e) {
			return null;
		}
		
	}

	@Override
	@Transactional
	public Question addReponsesCorrectesToQuestion(String idQuestion, List<String> idReponsesCorrectes) throws Exception {
		
		if(checkIfReponsesCorrectesIsSubsetOfReponseEventuelles(idQuestion, idReponsesCorrectes)){
			Question question = questionDao.findById(Integer.parseInt(idQuestion));
			
			List<Reponse> reponsesCorrectes = new ArrayList<Reponse>();
			for(String idReponse : idReponsesCorrectes){
				Reponse reponse = reponseDao.findById(Integer.parseInt(idReponse));
				reponsesCorrectes.add(reponse);
			}
			
			question.setReponsesCorrectes(reponsesCorrectes);
			
			try{
				question = questionDao.merge(question);
				return question;
			} catch (Exception e) {
				return null;
			}
		}
		
		return null;
	}
	
	/**
	 * Verifie si la liste des réponses correctes est un sous ensemble de la liste des réponses éventuelles. 
	 * @param idQuestion
	 * @param idReponsesCorrectes
	 * @return
	 */
	@Transactional
	private boolean checkIfReponsesCorrectesIsSubsetOfReponseEventuelles(String idQuestion, List<String> idReponsesCorrectes) {

		Question question = questionDao.findById(Integer.parseInt(idQuestion));
		
		List<Reponse> reponsesEventuelles = question.getReponsesEventuelles();
		
		List<String> idReponsesEventuelles = new ArrayList<String>();
		for(Reponse reponse : reponsesEventuelles){
			idReponsesEventuelles.add(reponse.getIdReponse().toString());
		}
		
		return idReponsesEventuelles.containsAll(idReponsesCorrectes);
	}

	@Override
	public Reponse creerReponse(Reponse reponse) throws Exception {
		try{
			return reponseDao.persist(reponse);
		} catch (Exception e) {
			throw e;
		}
	}

	@Override
	public Reponse modifierReponse(Reponse reponse) throws Exception {
		try{
			return reponseDao.merge(reponse);
		} catch (Exception e) {
			throw e;
		}
	}

	@Override
	public Categorie createCategorie(Categorie categorie) throws Exception {
		try{
			return categorieDao.persist(categorie);
		} catch(Exception e){
			throw e;
		}
	}

	@Override
	@Transactional
	public void deleteCategorie(String idCategorie) throws Exception {
		try{
			Categorie categorie = categorieDao.findById(Integer.parseInt(idCategorie));
			categorieDao.remove(categorie);
		} catch (Exception e) {
			throw e;
		}
	}

}
